﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using HAUtil;

using DotSpatial.Topology;


namespace HA.Data
{
    [Serializable]
    public class PolygonFO:FeatureObject
    {
        public PolygonFO(string id, List<HCoordinate> coords,List<List<HCoordinate>> holes,Coverage coverage)
            : base(id,coverage)
        {

            this._coords = coords;
            if (holes.Count <= 0)
                this._innerHoles = new List<List<HCoordinate>>();
            else 
                this._innerHoles = holes;

            this._mapColor = new MapDataColor();


            //int nPeriods = this.Parent.ParentCM.Model.NPeriods;
            this._specifiedFlow = new BCSpecifiedFlow();

            List<string> lstNames = new List<string>();
            foreach (MT3DMS.DomainLayer.MTSpecies item in coverage.ParentCM.Model.SpeList)
            {
                lstNames.Add(item.Name);
            }

            this._arealPropertyData = new ArealPropertyData(lstNames);

        }

        public PolygonFO(string id, string polylineKey, List<HCoordinate> coords, List<List<HCoordinate>> holes, Coverage coverage )
            : base(id,coverage)
        {

            this._coords = coords;
            if (holes.Count <= 0)
                this._innerHoles = new List<List<HCoordinate>>();
            else
                this._innerHoles = holes;

            this._mapColor = new MapDataColor();


            //int nPeriods = this.Parent.ParentCM.Model.NPeriods;

            this._specifiedFlow = new BCSpecifiedFlow();
            this._polyKey = polylineKey;

            List<string> lstNames = new List<string>();
            foreach (MT3DMS.DomainLayer.MTSpecies item in coverage.ParentCM.Model.SpeList)
            {
                lstNames.Add(item.Name);
            }

            this._arealPropertyData = new ArealPropertyData(lstNames);

        }

        #region New

        /// <summary>
        /// 该函数进行的是多边形更新时需要的 额外 操作
        /// </summary>
        /// <param name="type"></param>
        public void UpdateForPolygonFOChanged(CollectionChangedType type)
        {
            switch (type)
            {
                case CollectionChangedType.REMOVE: //删除多边形

                    foreach (LineAndDirection line in this.RelationLines)
                    {
                        for (int i = line.Line.RelatedPolygonFO.Count - 1; i >= 0; i--)
                        {
                            if (line.Line.RelatedPolygonFO[i].Id == this.Id)
                                line.Line.RelatedPolygonFO.RemoveAt(i);
                        }
                        //if (line.Line.RelatedPolygonFO.Contains(this))
                        //{
                        //    line.Line.RelatedPolygonFO.Remove(this);
                        //}
                    }

                    foreach (List<LineAndDirection> item in this._holeRelationLines)
                    {
                        foreach (LineAndDirection line in item)
                        {
                            for (int i = line.Line.RelatedPolygonFO.Count - 1; i >= 0; i--)
                            {
                                if (line.Line.RelatedPolygonFO[i].Id == this.Id)
                                    line.Line.RelatedPolygonFO.RemoveAt(i);
                            }
                            //if (line.Line.RelatedPolygonFO.Contains(this))
                            //{
                            //    line.Line.RelatedPolygonFO.Remove(this);
                            //}
                        }
                    }


                    break;

                default:
                    break;
            }
        }


        
        /// <summary>
        /// 新结构
        /// 环中不存储闭合尾点
        /// </summary>
        /// <param name="id"></param>
        /// <param name="lineFOes">key为线信息，value为方向正向为1或反向为-1</param>
        /// <param name="innerHolelineFOes"></param>
        public PolygonFO(string id, List<LineAndDirection> lineFOes, List<List<LineAndDirection>> innerHolelineFOes,Coverage coverage)
            : base(id,coverage)
        {
            ///构建多边形代码
            ///待添加
            this._relationLines = lineFOes;
            this._holeRelationLines = innerHolelineFOes == null ? new List<List<LineAndDirection>>() : innerHolelineFOes;

            this.BuildPolygon();

            this._mapColor = new MapDataColor();

            int nPeriods = coverage.ParentCM.Model.NPeriods;
            this._specifiedFlow = new BCSpecifiedFlow();

            List<string> lstNames = new List<string>();
            foreach (MT3DMS.DomainLayer.MTSpecies item in coverage.ParentCM.Model.SpeList)
            {
                lstNames.Add(item.Name);
            }

            this._arealPropertyData = new ArealPropertyData(lstNames);
        }

        /// <summary>
        /// 初始化多边形坐标点信息
        /// </summary>
        public void BuildPolygon()
        {
            if (this._relationLines == null || this._relationLines.Count == 0)
                throw new Exception("多边形线信息不能为空！");

            this._coords.Clear();
            this._innerHoles.Clear();

            foreach (LineAndDirection item in _relationLines)
            {
                _coords.AddRange(item.Line.ToCoordinatesArray(item.Direction));
                _coords.RemoveAt(_coords.Count - 1);
            }

            if (_holeRelationLines.Count > 0)
            {
                bool isOuterCoordsNeedReverse = false;

                List<Coordinate> coords = new List<Coordinate>();
                for (int i = 0; i < _coords.Count; i++)
                {
                    coords.Add(new Coordinate(_coords[i].X, _coords[i].Y));
                }
                Polygon outerRingPoly = new Polygon(coords);

                List<HCoordinate> hole;


                Polygon holePoly = outerRingPoly;

                for (int i = _holeRelationLines.Count-1; i >=0; i--)
                {
                    hole = new List<HCoordinate>();
                    foreach (LineAndDirection item in _holeRelationLines[i])
                    {
                        hole.AddRange(item.Line.ToCoordinatesArray(item.Direction));
                        hole.RemoveAt(hole.Count - 1);
                    }

                    if (hole.Count > 2)
                    {
                        coords = new List<Coordinate>();

                        for (int j = 0; j < hole.Count; j++)
                        {
                            coords.Add(new Coordinate(hole[j].X, hole[j].Y));
                        }

                        Polygon innerRingPoly = new Polygon(coords);

                        if (holePoly.Contains(innerRingPoly))
                        {
                            IGeometry dirPolygon = holePoly.Difference(innerRingPoly);
                            if ((holePoly = (dirPolygon as Polygon)) != null)
                            {
                                for (int k = 0; k < holePoly.Shell.Coordinates.Count; k++)
                                {
                                    if (_coords[0].X == holePoly.Shell.Coordinates[k].X && _coords[0].Y == holePoly.Shell.Coordinates[k].Y)
                                    {
                                        if (holePoly.Shell.Coordinates.Count - 1 > k)
                                        {
                                            if (!(_coords[1].X == holePoly.Shell.Coordinates[k + 1].X && _coords[1].Y == holePoly.Shell.Coordinates[k + 1].Y))
                                            {
                                                isOuterCoordsNeedReverse = true;
                                            }

                                        }
                                        else
                                        {
                                            if ((_coords[1].X == holePoly.Shell.Coordinates[k - 1].X && _coords[1].Y == holePoly.Shell.Coordinates[k - 1].Y))
                                            {
                                                isOuterCoordsNeedReverse = true;
                                            }
                                        }
                                        break;
                                    }
                                }


                                for (int j = 0; j < holePoly.Holes[holePoly.Holes.Length - 1].Coordinates.Count; j++)
                                {
                                    if (hole[0].X == holePoly.Holes[holePoly.Holes.Length - 1].Coordinates[j].X && hole[0].Y == holePoly.Holes[holePoly.Holes.Length - 1].Coordinates[j].Y)
                                    {
                                        if (holePoly.Holes[holePoly.Holes.Length - 1].Coordinates.Count - 1 > j)
                                        {
                                            if (!(hole[1].X == holePoly.Holes[holePoly.Holes.Length - 1].Coordinates[j + 1].X && hole[1].Y == holePoly.Holes[holePoly.Holes.Length - 1].Coordinates[j + 1].Y))
                                            {
                                                hole.Reverse();
                                            }
                                        }
                                        else
                                        {
                                            if ((hole[1].X == holePoly.Holes[holePoly.Holes.Length - 1].Coordinates[j - 1].X && hole[1].Y == holePoly.Holes[holePoly.Holes.Length - 1].Coordinates[j - 1].Y))
                                            {
                                                hole.Reverse();
                                            }
                                        }
                                        break;
                                    }

                                }

                                this._innerHoles.Add(hole);
                            }
                        }//if 包含
                        else
                        {
                            for (int j = 0; j < _holeRelationLines[i].Count; j++)
                            {
                                _holeRelationLines[i][j].Line.RelatedPolygonFO.Remove(this);
                            }

                            _holeRelationLines.RemoveAt(i);
                        }
                    }//if hole坐标有效
                }//for 循环洞信息

                if (isOuterCoordsNeedReverse)
                    _coords.Reverse();
            }//if有洞
        }



        List<LineAndDirection> _relationLines;
        /// <summary>
        /// 构成多边形外环的线 
        /// Key表示弧线，value表示弧线方向
        /// </summary>
        public List<LineAndDirection> RelationLines
        {
            get { return _relationLines; }
            set { _relationLines = value; }
        }

        List<List<LineAndDirection>> _holeRelationLines;
        /// <summary>
        /// 构成多边形洞的线
        /// Key表示弧线，value表示弧线方向
        /// </summary>
        public List<List<LineAndDirection>> HoleRelationLines
        {
            get { return _holeRelationLines; }
            set { _holeRelationLines = value; }
        }




        #endregion


        string _polyKey = "";

        public string PolyKey
        {
            get { return _polyKey; }
            set { _polyKey = value; }
        }


        List<HCoordinate> _coords = new List<HCoordinate>();

        public List<HCoordinate> Coords
        {
            get { return _coords; }
            set { _coords = value; }
        }

        List<List<HCoordinate>> _innerHoles = new List<List<HCoordinate>>();
        /// <summary>
        /// 多边形洞
        /// </summary>
        public List<List<HCoordinate>> InnerHoles
        {
            get { return _innerHoles; }
            set { _innerHoles = value; }
        }


        MapDataColor _mapColor;

        public MapDataColor MapColor
        {
            get { return _mapColor; }
            set { _mapColor = value; }
        }



        BCSpecifiedFlow _specifiedFlow;

        public BCSpecifiedFlow SpecifiedFlow
        {
            get { return _specifiedFlow; }
            set { _specifiedFlow = value; }
        }


        #region 多边形特有的属性,只在无bctype时输入

        ArealPropertyData _arealPropertyData;

        public ArealPropertyData ArealPropertyData
        {
            get { return _arealPropertyData; }
           
        }


        #endregion

        public override void ResetCoords(List< HAUtil.HCoordinate> coords)
        {
            this._coords.Clear();
            this._coords.AddRange(coords);
        }


        public override void MapToModFlow(List<double> stressPeriods, ModFlow.Domain.DomainLayer.ModFlowData mf, CoverageSetup setup)
        {
            base.MapToModFlow(stressPeriods, mf,setup);

            BCType bc = this.GetCurrentBCType();


            //当并未设置BC时，可以设置对应的面妆源汇属性

            if (bc == null)
            {

              

                List<ValueResult> ijkList = this.LstIJK;


                this._arealPropertyData.MaptoModflow(stressPeriods,mf,setup,ijkList );


            }
            else
            {

 
            }
          



        }


        public override void MapToMT3dMS(List<double> stressPeriods, MT3DMS.DomainLayer.MT3DMSData data, CoverageSetup setup)
        {
            base.MapToMT3dMS(stressPeriods, data, setup);

            BCMT3DMS bc = this.GetCurrentMTType();


            //当并未设置BC时，可以设置对应的面妆源汇属性

            if (bc == null)
            {


                List<ValueResult> ijkList = this.LstIJK;


                this._arealPropertyData.MapToMt3dms(stressPeriods, setup,ijkList, data);


            }
            else
            {


            }



        }




        public override object Clone()
        {
            
            PolygonFO poly=(PolygonFO) base.Clone();

            poly._relationLines = new List<LineAndDirection>();
            poly._relationLines.AddRange(_relationLines);

            poly._holeRelationLines = new List<List<LineAndDirection>>();
            foreach (List<LineAndDirection> list in _holeRelationLines)
            {
                List<LineAndDirection> holeLines = new List<LineAndDirection>();
                holeLines.AddRange(list);
                poly._holeRelationLines.Add(holeLines);
            }

            poly._coords = new List<HCoordinate>();
            foreach (HCoordinate item in this._coords)
            {
                poly._coords.Add((HCoordinate)item.Clone());
            }

            poly._innerHoles = new List<List<HCoordinate>>();
            List<HCoordinate> hole;
            foreach (List<HCoordinate> item in this._innerHoles)
            {
                hole = new List<HCoordinate>();
                foreach (HCoordinate coord in item)
                {
                    hole.Add((HCoordinate)coord.Clone());
                }
                poly._innerHoles.Add(hole);
            }


            poly._specifiedFlow = (BCSpecifiedFlow)this._specifiedFlow.Clone();

            poly._mapColor = (MapDataColor)this._mapColor.Clone();

            poly._arealPropertyData =(ArealPropertyData) this._arealPropertyData.Clone();

            return poly;
        }



        //internal override void OnNPeriodsChanged(int nPeriods)
        //{

        //    base.OnNPeriodsChanged(nPeriods);

        //    this._specifiedFlow.NPeriods = nPeriods;

        //    this._arealPropertyData.RechargeConc.NPeriods = nPeriods;

        //    this._arealPropertyData.RechargeRate.NPeriods = nPeriods;
        //    this._arealPropertyData.EtExtDepthV2.NPeriods = nPeriods;
        //    this._arealPropertyData.EtRateV2.NPeriods = nPeriods;
        //    this._arealPropertyData.MaxETRateV2.NPeriods = nPeriods;
        //}

        internal override void OnSpeListChanged(List<string> lst)
        {
            base.OnSpeListChanged(lst);

            this._arealPropertyData.RechargeConc.OnSpeListChanged(lst);
            this._arealPropertyData.Startingconcentration.OnSpeListChanged(lst);
        }

        protected override void BuildIJKList(DotSpatial.Topology.Polygon[,] polys, List<int[,]> ibound, Polygon polyGridFrame, int From, int To)
        {
            this._lstIJK.Clear();


            int nlayers = ibound.Count;






         


            List<Coordinate> coord = new List<Coordinate>();
            foreach (HAUtil.HCoordinate hc in this.Coords)
            {
                Coordinate c = new Coordinate(hc.X, hc.Y);
                coord.Add(c);
            }

            List<List<Coordinate>> holes = new List<List<Coordinate>>();

            List<Coordinate> hole;

            if (this.InnerHoles != null && this.InnerHoles.Count > 0)
            {
                foreach (List<HAUtil.HCoordinate> holehc in this.InnerHoles)
                {
                    hole = new List<Coordinate>();
                    foreach (HAUtil.HCoordinate hCoordinate in holehc)
                    {
                        Coordinate c = new Coordinate(hCoordinate.X, hCoordinate.Y);
                        hole.Add(c);
                    }
                    holes.Add(hole);
                }
            }





            List<LinearRing> lstHoles = new List<LinearRing>();

            foreach (List<Coordinate> l in holes)
            {
                LinearRing lr = new LinearRing(l);

                lstHoles.Add(lr);


            }


            LinearRing lrOut = new LinearRing(coord);


            ///本层所指示的多边形
            Polygon p;

            if (holes.Count > 0)
            {

                p = new Polygon(lrOut, lstHoles.ToArray());


            }
            else
            {
                p = new Polygon(lrOut);
            }











            int nrows = polys.GetLength(0);

            int ncols = polys.GetLength(1);


            for (int k = From - 1; k < To; k++)
            {

                ///当i在有效范围的时候,这里的i 对应的图层的索引

                if (k < nlayers && k > -1)
                {

                    for (int i = 0; i < nrows; i++)
                    {

                        for (int j = 0; j < ncols; j++)
                        {


                         


                                //判断有效性

                                if (ibound[k][i, j] != 0)
                                {


                                    if (polys[i, j].Intersects(p))
                                    {


                                        try
                                        {

                                            IGeometry ig = polys[i, j].Intersection(p);

                                            ValueResult vr = new ValueResult(i + 1, j + 1, k + 1, ig.Area);

                                            this._lstIJK.Add(vr);


                                        }
                                        catch (Exception)
                                        {
                                            

                                            //当某一个映射出错时，不影响其他的类型

                                            Console.WriteLine("警告polygon遇到不可映射的图形");
                                            
                                        }



                                      





                                    }





                                  



                                }






                          




                        }

                    }





                }

            }
        }


        protected internal override BCType GetCurrentBCType()
        {
            BCType bc = base.GetCurrentBCType();
            if (bc == null)
            {
                if (this._selectedSCType == MAPSCType.SPECIFIEDFLOW)
                {
                    bc = this._specifiedFlow;


                }

              

            }

            return bc;

        }


      





    }
}
